﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Newtonsoft.Json;

namespace CommandExecutor
{
    public interface Command<T, TResult>
    {
        TResult Call(T param);
    }

	public class RCServer
    {
        Dictionary<String, Func<String, String>> handlers = new Dictionary<string, Func<string, string>>();

        public void AddCommandHandler<T, TResult>(string command, Func<T, TResult> handler)
        {
            handlers.Add(command, paramAsString =>
              {
                  var param = JsonConvert.DeserializeObject<T>(paramAsString);
                  var res = handler(param);
                  return JsonConvert.SerializeObject(res);
              });
        }

        public void AddCommandHandler<T, TResult>(string command, Command<T, TResult> c)
        {
            AddCommandHandler<T, TResult>(command, c.Call);
        }

        public void Listen()
        {
            var myList = new TcpListener(IPAddress.Any, 8001);
            myList.Start();

            TcpClient tcpClient = myList.AcceptTcpClient();

            var b = new byte[1024];
            NetworkStream stream = tcpClient.GetStream();
            int k = stream.Read(b, 0, b.Length);
            var textReceived = Encoding.UTF8.GetString(b, 0, k);

            var command = JsonConvert.DeserializeObject<Command>(textReceived);
            ResultCommand resultCommand = new ResultCommand();
            try
            {
	            resultCommand.Result = handlers[command.CommandName](command.Parameter);
	            resultCommand.Success = true;
            }
            catch (Exception e)
            {
            	resultCommand.Success = false;
            	resultCommand.ErrorMessage = e.Message;
            	resultCommand.ErrorStackTrace = e.StackTrace;
            }

            var response = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(resultCommand));
            stream.Write(response, 0, response.Length);
            stream.Close();
            tcpClient.Close();
            myList.Stop();     
        }
    }
}
